package org.wltea.expression.function;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jayway.jsonpath.JsonPath;

import java.util.Calendar;
import java.util.Date;

/**
 * Created by Jerry on 2017/4/27.
 */
public class JsonFunctions {

    private static final String EMPTY_STRING = "";

    private static final Integer EMPTY_INTEGER = -99;

    private static final Long EMPTY_LONG = -99L;

    private static final Double EMPTY_DOUBLE = -99D;

    private static final String EMPTY_DATE = "99991231";

    private static final String FALSE_CODE = "500";
    private static final String TRUE_CODE = "200";


    //private static final Long EMPTY_DATE = -1L;

    /**
     * get single String value
     *
     * @param jsonString
     * @param keys
     * @return
     */
    public String getJsonString(String jsonString, String keys) {

        if (jsonString == null || keys == null)
            return EMPTY_STRING;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return EMPTY_STRING;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return EMPTY_STRING;

        String key = keyArray[keyArray.length - 1].trim();
        String result = jsonObject.getString(key);
        return result == null ? EMPTY_STRING : result;
    }

    /**
     * get single String value  def
     *
     * @param jsonString
     * @param keys
     * @return
     */
    public String getJsonStringDef(String jsonString, String keys, String def) {

        if (jsonString == null || keys == null)
            return def;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return def;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return def;

        String key = keyArray[keyArray.length - 1].trim();
        String result = jsonObject.getString(key);
        return result == null ? def : result;
    }

    /**
     * get single Integer value
     *
     * @param jsonString
     * @param keys
     * @return
     */
    public Integer getJsonInteger(String jsonString, String keys) {

        if (jsonString == null || keys == null)
            return EMPTY_INTEGER;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return EMPTY_INTEGER;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return EMPTY_INTEGER;

        String key = keyArray[keyArray.length - 1].trim();
        Integer result = jsonObject.getInteger(key);
        return result == null ? EMPTY_INTEGER : result;
    }


    public Double getJsonPercentDouble(String jsonString, String keys) {

        String percentValue = getJsonString(jsonString, keys);
        if (percentValue == null || EMPTY_STRING.equals(percentValue))
            return EMPTY_DOUBLE;

        percentValue = percentValue.replace("%", "");
        Double value = Double.parseDouble(percentValue);
        if (value == null)
            return EMPTY_DOUBLE;

        return value / 100;
    }


    /**
     * get array size
     *
     * @param jsonString
     * @param keys
     * @return
     */
    public Integer getJsonArraySize(String jsonString, String keys) {

        JSONArray jsonArray = parseJSONArray(jsonString, keys);
        if (jsonArray == null)
            return EMPTY_INTEGER;

        Integer result = jsonArray.size();
        return result;
    }


    public Integer getSizeForJsonArray(String jsonString) {

        JSONArray jsonArray = JSONArray.parseArray(jsonString);
        if (jsonArray == null)
            return EMPTY_INTEGER;

        Integer result = jsonArray.size();
        return result;
    }


    /**
     * json array size的二次封装
     *
     * @param jsonString
     * @param keys
     * @return
     */
    public String getJsonArrayState(String jsonString, String keys) {

        Integer size = getJsonArraySize(jsonString, keys);
        if (EMPTY_INTEGER.equals(size))
            return EMPTY_STRING;

        else if (size == 0)
            return "无";
        else
            return "有";

    }

    /**
     * get array size by condition
     *
     * @param jsonString
     * @param keys
     * @param condition
     * @return
     */
    public Integer getJsonArraySizeByCondition(String jsonString, String keys, String condition) {

        if (condition == null)
            return EMPTY_INTEGER;

        JSONArray jsonArray = parseJSONArray(jsonString, keys);
        if (jsonArray == null)
            return EMPTY_INTEGER;

        String[] tempArray = condition.split(":");
        if (tempArray == null || tempArray.length != 2)
            return EMPTY_INTEGER;

        String conditionKey = tempArray[0].trim();  //for condition check
        String conditionValue = tempArray[1].trim();

        int count = 0;
        for (int i = 0; i < jsonArray.size(); i++) {
            if (conditionValue.equals(jsonArray.getJSONObject(i).getString(conditionKey)))
                count++;
        }

        return count;
    }

    /**
     * get multiple values (separated by comma), from json array
     *
     * @param jsonString
     * @param keys
     * @param selectKeys
     * @return
     */
    public String getJsonArrayValues(String jsonString, String keys, String selectKeys) {

        if (selectKeys == null)
            return EMPTY_STRING;

        JSONArray jsonArray = parseJSONArray(jsonString, keys);
        if (jsonArray == null)
            return EMPTY_STRING;

        StringBuilder builder = new StringBuilder(EMPTY_STRING); //for empty array

        for (int i = 0; i < jsonArray.size(); i++) {

            JSONObject tempJson = jsonArray.getJSONObject(i);

            //builder.append(jsonArray.getJSONObject(i).getString(selectKeys));
            String[] selectKeyArray = selectKeys.split(",");
            for (int j = 0; j < selectKeyArray.length - 1; j++) {
                tempJson = tempJson.getJSONObject(selectKeyArray[j]);
                if (tempJson == null)
                    return EMPTY_STRING;
            }
            builder.append(tempJson.getString(selectKeyArray[selectKeyArray.length - 1]));

            if (i < jsonArray.size() - 1)
                builder.append(",");
        }

        return builder.toString();
    }

    /**
     * get integer sum of json object multiple properties
     *
     * @param jsonString
     * @param keys
     * @param properties
     * @return
     */
    public Integer getJsonIntegerSum(String jsonString, String keys, String properties) {

        if (jsonString == null || keys == null || properties == null)
            return EMPTY_INTEGER;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return EMPTY_INTEGER;

        String[] propertyArray = properties.split(",");
        if (propertyArray == null || propertyArray.length == 0)
            return EMPTY_INTEGER;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return EMPTY_INTEGER;

        String key = keyArray[keyArray.length - 1].trim();
        JSONObject jsonObject2 = jsonObject.getJSONObject(key);
        if (jsonObject2 == null)
            return EMPTY_INTEGER;

        int sum = 0;
        for (int i = 0; i < propertyArray.length; i++)
            sum += jsonObject2.getIntValue(propertyArray[i].trim());

        return sum;
    }

    /**
     * get string property for the first element of json array
     * selectKeys can be multiple value separated by comma
     *
     * @param jsonString
     * @param keys
     * @param selectKeys
     * @return
     */
    public String getJsonArrayFirstItemValueString(String jsonString, String keys, String selectKeys) {

        String values = getJsonArrayValues(jsonString, keys, selectKeys);
        if (values == null || EMPTY_STRING.equals(values))
            return EMPTY_STRING;

        String[] valueArray = values.split(",");
        if (valueArray == null || valueArray.length == 0)
            return EMPTY_STRING;

        String value = valueArray[0];
        if (value == null)
            return EMPTY_STRING;

        return value;
    }

    /**
     * get json array integer property sum
     *
     * @param jsonString
     * @param keys
     * @param property
     * @return
     */
    public Integer getJsonArrayPropertySum(String jsonString, String keys, String property) {

        if (property == null)
            return EMPTY_INTEGER;

        JSONArray jsonArray = parseJSONArray(jsonString, keys);
        if (jsonArray == null)
            return EMPTY_INTEGER;

        int sum = 0;
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            if (item == null)
                continue;

            sum += item.getIntValue(property.trim());
        }

        return sum;
    }

    /**
     * get string property for the first element of json array
     *
     * @param jsonString
     * @param keys
     * @param selectKeys
     * @return
     */
    public String getJsonArrayFirstItemPropertyString(String jsonString, String keys, String selectKeys) {

        if (selectKeys == null)
            return EMPTY_STRING;

        JSONArray jsonArray = parseJSONArray(jsonString, keys);
        if (jsonArray == null || jsonArray.isEmpty()) // notice to check whether json array is empty
            return EMPTY_STRING;

        String value = parseJSONArrayString(jsonArray, selectKeys, 0);
        /*
        // get first element
        JSONObject jsonObject = jsonArray.getJSONObject(0);
        if (jsonObject == null)
            return EMPTY_STRING;

        // get property value
        String[] selectKeyArray = selectKeys.split(",");
        String value = jsonObject.getString(property.trim());
        */
        if (value == null)
            return EMPTY_STRING;

        return value;
    }

    public String getJsonStringResultToNULL(String jsonString, String keys) {

        if (jsonString == null || keys == null)
            return EMPTY_STRING;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return EMPTY_STRING;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return EMPTY_STRING;

        String key = keyArray[keyArray.length - 1].trim();
        String result = jsonObject.getString(key);
        return result;
    }

    /**
     * parse json object to the second last key utility
     *
     * @param jsonString
     * @param keyArray
     * @return
     */
    private JSONObject parseJSONObject(String jsonString, String[] keyArray) {

        JSONObject jsonObject = JSON.parseObject(jsonString);

        for (int i = 0; i < keyArray.length - 1; i++) {
            //validation check
            if (jsonObject == null)
                return null;
            try {
                jsonObject = jsonObject.getJSONObject(keyArray[i].trim());
            } catch (Exception e) {
                return null;
            }
        }

        return jsonObject;
    }

    /**
     * get json array utility
     *
     * @param jsonString
     * @param keys
     * @return
     */
    private JSONArray parseJSONArray(String jsonString, String keys) {

        if (jsonString == null || keys == null)
            return null;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return null;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return null;

        String key = keyArray[keyArray.length - 1].trim();
        JSONArray jsonArray = jsonObject.getJSONArray(key);
        if (jsonArray == null)
            return null;

        return jsonArray;
    }

    private String parseJSONArrayString(JSONArray jsonArray, String keys, Integer index) {

        if (jsonArray == null || keys == null || index == null || jsonArray.size() <= index)
            return null;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return null;

        JSONObject jsonObject = jsonArray.getJSONObject(index);
        for (int i = 0; i < keyArray.length - 1; i++) {
            //validation check
            if (jsonObject == null)
                return null;

            jsonObject = jsonObject.getJSONObject(keyArray[i].trim());
        }

        return jsonObject.getString(keyArray[keyArray.length - 1].trim());
    }

    /**
     * get Date from year, month and day
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    private Date getDate(Integer year, Integer month, Integer day) {

        if (year == null || month == null || day == null)
            return null;

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        return calendar.getTime();
    }

    private Date convertString2Date(String value, String separator) {

        if (value == null || separator == null)
            return null;

        String[] valueArray = value.split(separator);
        if (valueArray == null || valueArray.length != 3)
            return null;

        String yearString = valueArray[0].trim();
        String monthString = valueArray[1].trim();
        String dayString = valueArray[2].trim();

        if (EMPTY_STRING.equals(yearString) || EMPTY_STRING.equals(monthString) || EMPTY_STRING.equals(dayString))
            return null;

        Integer year = Integer.parseInt(yearString);
        Integer month = Integer.parseInt(monthString);
        Integer day = Integer.parseInt(dayString);

        Date date = getDate(year, month, day);

        return date;
    }

    private Integer monthsBeforeToday(Date date) {

        Date today = new Date();

        long dayCount = (today.getTime() - date.getTime()) / (3600 * 24 * 1000);

        long monthCount = dayCount / 31;

        return (int) monthCount;
    }

    public String spCode(String jsonString, String keys) {

        if (jsonString == null || keys == null)
            return FALSE_CODE;

        String[] keyArray = keys.split(",");
        if (keyArray == null || keyArray.length == 0)
            return FALSE_CODE;

        JSONObject jsonObject = parseJSONObject(jsonString, keyArray);
        //validation check
        if (jsonObject == null)
            return FALSE_CODE;

        String key = keyArray[keyArray.length - 1].trim();
        String result = jsonObject.getString(key);
        return result != null && result.equals(TRUE_CODE) ? TRUE_CODE : FALSE_CODE;
    }

    public Object parseJSONObject(String jsonString) {
        JSONObject object = JSON.parseObject(jsonString);
        return object;
    }

    public Object getJSONPathValue(Object data, String path) {
        if (data == null) {
            return null;
        }
        return JsonPath.read(data, path);
    }

}
